# -*- coding: utf-8 -*-
# @Time    : 2025/5/11 16:03
# @Author  : cx
# @File    : mysql_database_utils_Y.py
# @Software: PyCharm
import aiomysql
from typing import List, Tuple, Optional
import logging

# 创建日志记录器
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class AsyncMYSQL_L:
    """
    协程方式下的MYSQL数据库操作
    """
    def __init__(self, host, port, user, password, database, minsize=2, maxsize=8, autocommit=False,
                 pool_recycle=300):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.minsize = minsize
        self.maxsize = maxsize
        self.autocommit = autocommit
        self.pool_recycle = pool_recycle
        self.__pool = None

    async def create_pool(self):
        """
        创建异步连接池（推荐在程序启动时调用）
        aiomysql.create_pool：aiomysql 库提供的异步函数，用于创建 MySQL 数据库连接池
        """
        self.__pool = await aiomysql.create_pool(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            db=self.database,
            minsize=self.minsize,  # 最小连接数（相当于 mincached）
            maxsize=self.maxsize,  # 最大连接数（相当于 maxconnections）
            autocommit=self.autocommit,  # 关闭自动提交
            pool_recycle=self.pool_recycle  # 连接回收时间（秒）
        )

    async def close_pool(self):
        """关闭连接池（推荐在程序退出时调用）"""
        if self.__pool:
            # 标记连接池为 “关闭状态”，停止接受新的连接请求,这是一个同步操作（无需 await）
            # close() 是 aiomysql.Pool 类的方法，调用后连接池会拒绝新的连接请求（如 acquire() 获取连接会失败），
            # 但不会立即关闭所有正在使用的连接
            self.__pool.close()
            # 异步等待连接池完全关闭（所有连接被释放）
            await self.__pool.wait_closed()

    @property  # 装饰器作用:只读属性
    def pool(self):
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")
        return self.__pool

    async def execute(self, operation_type, sql, params=None):
        """
        全能数据库操作方法
        :param operation_type: 查询操作（SELECT）：执行查询并返回结果集。
                                修改操作（INSERT/UPDATE/DELETE）：执行修改并提交事务，返回操作是否成功。
        :param sql:SQL语句
        :param params:
        :return:成功:True, 失败:False, 查询无结果:空[]
        查询操作
        result = await db.execute("SELECT", "SELECT * FROM users WHERE age > %s", (18,))
        插入操作
        success = await db.execute("INSERT", "INSERT INTO users (name, age) VALUES (%s, %s)", ("Alice", 25))
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")

        async with self.__pool.acquire() as conn:
            async with conn.cursor() as cursor:
                try:
                    if operation_type == "SELECT":
                        await cursor.execute(sql, params or ())
                        return await cursor.fetchall()
                    elif operation_type in ["INSERT", "UPDATE", "DELETE"]:
                        await cursor.execute(sql, params or ())
                        await conn.commit()
                        return True
                    else:
                        raise ValueError("不支持的操作类型")
                except aiomysql.Error as e:
                    logger.error(f"执行SQL时出错: {sql}, 参数: {params}, 错误: {e}")
                    if operation_type in ["INSERT", "UPDATE", "DELETE"]:
                        await conn.rollback()
                        logger.error("事务已回滚，原因是SQL执行错误")
                    return False
                except Exception as e:
                    logger.error(f"执行操作时发生意外错误: {e}")
                    if operation_type in ["INSERT", "UPDATE", "DELETE"]:
                        await conn.rollback()
                        logger.error("事务已回滚，原因是发生意外错误")
                    return False

    """
        sql: str：要执行的 SQL 查询语句
        params: tuple = None：SQL 语句的参数（可选），用于填充 SQL 中的占位符（如 %s）。默认值为 None，表示无参数。
        -> 符号：这是 Python 的函数返回值类型标注语法，用于声明函数返回值的类型
        -> Optional[List[Tuple]] 表示函数返回值的类型
            成功时：返回一个 List[Tuple]（元组列表）
            失败时：返回 None（如连接池未初始化、SQL 执行错误等）
        """

    async def execute_query(self, sql: str, params: tuple = None) -> Optional[List[Tuple]]:
        """
        通用异步查询方法
        :param sql: SQL 查询语句
        :param params: 查询参数
        :return: 查询结果列表或 None（失败时）
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")
        # async with 上下文管理器：确保连接和游标在代码块执行完毕后自动释放（归还给连接池或关闭），避免资源泄漏
        # self.__pool.acquire()：从连接池中异步获取一个数据库连接（aiomysql.Connection 对象
        # as 关键字的作用是将异步上下文管理器返回的资源对象（这里是数据库连接）绑定到一个变量（conn）
        async with self.__pool.acquire() as conn:
            # conn.cursor()：通过连接创建一个游标（aiomysql.Cursor 对象），游标是执行 SQL 语句和获取结果的接口
            async with conn.cursor() as cursor:
                try:
                    # cursor.execute(sql, params)：异步执行 SQL 语句。params 用于填充 SQL 中的占位符（如 %s），
                    # 这种方式可以防止 SQL 注入攻击（替代直接拼接字符串
                    # 若 params 为 None，则 params or () 会将其转换为空元组（()），避免 execute 方法因参数缺失报错
                    await cursor.execute(sql, params or ())
                    # cursor.fetchall()：异步获取所有查询结果（即数据库返回的所有行）。返回值是一个元组列表
                    results = await cursor.fetchall()
                    #result = await cursor.fetchone()  # 获取一条结果
                    return results if results else None # 无结果时返回 None
                except aiomysql.OperationalError as e:
                    # 处理数据库连接相关错误（如连接超时、权限不足）
                    error_code, error_msg = e.args
                    print(f"数据库操作错误 [{error_code}]: {error_msg}")
                    logger.error(f"数据库操作错误 [{error_code}]: {error_msg}")
                    if error_code in (2003, 2006, 2013):  # 连接拒绝/丢失
                        print("⚠️ 数据库连接失败，请检查主机、端口和权限")
                    return None
                except aiomysql.ProgrammingError as e:
                    # 处理SQL语法错误或参数不匹配
                    error_code, error_msg = e.args
                    print(f"SQL编程错误 [{error_code}]: {error_msg}")
                    print(f"错误SQL: {sql}")
                    print(f"参数: {params}")
                    logger.error(f"SQL编程错误 [{error_code}]: {error_msg}")
                    return None
                except aiomysql.IntegrityError as e:
                    # 处理数据完整性错误（如唯一约束冲突、外键失败）
                    error_code, error_msg = e.args
                    print(f"数据完整性错误 [{error_code}]: {error_msg}")
                    logger.error(f"数据完整性错误 [{error_code}]: {error_msg}")
                    return None
                except aiomysql.Error as e:
                    # 处理其他MySQL错误
                    error_code, error_msg = e.args
                    print(f"未知MySQL错误 [{error_code}]: {error_msg}")
                    logger.error(f"未知MySQL错误 [{error_code}]: {error_msg}")
                    return None
                except Exception as e:
                    # 处理非MySQL相关错误（如网络中断）
                    error_code, error_msg = e.args
                    print(f"执行查询时发生意外错误: {e}")
                    logger.error(f"执行查询时发生意外错误 [{error_code}]: {error_msg}")
                    return None

    async def execute_operate(self, sql_operations: List[Tuple[str, tuple]]) -> bool:
        """
        通用异步更新/插入方法，支持多个相关操作的事务控制
        :param sql_operations: 包含SQL语句及其参数的元组列表 [(sql1, params1), (sql2, params2), ...]
        :return: 执行是否成功
        sql =
            INSERT INTO zu_fang(tu_pian_di_zhi, tu_pian_bao_cun, ping_fang, gong_si,biao_ti,jia_ge,fa_bu_ri_qi,lian_jie,zhua_qu_shi_jian)
            VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)

        tu_pian_di_zhi = "example_path"
        tu_pian_bao_cun = "example_store"
        ping_fang = 100
        gong_si = "example_company"
        biao_ti = "example_title"
        jia_ge = 500
        fa_bu_ri_qi = "2024-01-01"
        lian_jie = "example_link"
        zhua_qu_shi_jian = "2024-01-01 00:00:00"

        params = (tu_pian_di_zhi, tu_pian_bao_cun, ping_fang, gong_si, biao_ti, jia_ge, fa_bu_ri_qi, lian_jie, zhua_qu_shi_jian)
        sql_operations = [(sql, params)]

        async def insert_data():
            success = await db.execute_update(sql_operations)
            if success:
                print("数据插入成功")
            else:
                print("数据插入失败，事务已回滚")
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")

        async with self.__pool.acquire() as conn:
            try:
                # 开始事务
                await conn.begin()

                for sql, params in sql_operations:
                    async with conn.cursor() as cursor:
                        try:
                            await cursor.execute(sql, params or ())
                        except aiomysql.Error as e:
                            # 记录详细的错误信息
                            logger.error(f"执行SQL时出错: {sql}, 参数: {params}, 错误: {e}")
                            # 回滚事务
                            await conn.rollback()
                            logger.error("事务已回滚，原因是SQL执行错误")
                            return False

                # 所有操作成功，提交事务
                await conn.commit()
                return True

            except Exception as e:
                # 记录其他异常信息
                logger.error(f"执行事务时发生意外错误: {e}")
                # 回滚事务
                await conn.rollback()
                logger.error("事务已回滚，原因是发生意外错误")
                return False


# 示例使用
async def main():
    db_pool = AsyncMYSQL_L('192.168.1.88', 3306, 'a18222970', 'cx123100', 'zhi_neng_wang_guan')
    await db_pool.create_pool()
    # 在这里可以使用 db_pool.pool 进行数据库操作
    await db_pool.close_pool()
